/*
 * @Descripttion: 写点什么
 * @version: 
 * @Author: Zhaocy
 * @Date: 2024-07-31 09:57:53
 * @LastEditors: Zhaocy
 * @LastEditTime: 2024-07-31 17:56:20
 */
package com.zhike.service.friends.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.zhike.common.dto.CMDBodyAddFriendRequest;
import com.zhike.common.dto.FriendBlackDTO;
import com.zhike.common.dto.FriendDeleteDTO;
import com.zhike.common.dto.FriendOfflineDTO;
import com.zhike.common.dto.FriendRemarkDTO;
import com.zhike.common.dto.FriendRequestDTO;
import com.zhike.common.dto.FriendUIdDTO;
import com.zhike.common.vo.OfflineFriendsRequestVO;
import com.zhike.common.dto.OfflineMsgDTO;
import com.zhike.common.dto.R;
import com.zhike.common.dto.UserRosterVO;
import com.zhike.common.dto.UserUIdDTO;
import com.zhike.common.enums.YesNoEnum;
import com.zhike.common.model.Roster;
import com.zhike.common.vo.RosterVO;
import com.zhike.common.vo.UserInfo4Cache;
import com.zhike.mapper.friends.FriendsMapper;
import com.zhike.service.friends.IFriendsService;
import com.zhike.service.im.manager.FriendMessageManager;
import com.zhike.service.messages.IMessagesService;
import com.zhike.service.user.IUserService;
import com.zhike.utils.cache.UsersInfoCacheProvider;
import cn.dev33.satoken.stp.StpUtil;
import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class FriendsServiceImpl implements IFriendsService {

  @Resource
  private FriendsMapper friendsMapper;

  @Autowired
  private FriendMessageManager friendMessageManager;

  @Resource
  private IMessagesService messagesService;

  @Resource
  private IUserService userService;

  @Autowired
  private UsersInfoCacheProvider usersInfoCacheProvider;

  @Override
  public Integer queryFriendsCountByUidFriendUid(String uid, String friendUid) {
    return friendsMapper.queryFriendsCountByUidFriendUid(uid, friendUid);
  }

  @Override
  public Boolean updateFriendsRequestTime(String desc, Long time, String uid, String friendUid) {
    return friendsMapper.updateFriendsRequestTime(desc, time, uid, friendUid) > 0;
  }

  @Override
  public Boolean insertFriendsRequestData(FriendRequestDTO dto) {
    String localUid = (String) StpUtil.getLoginId();
    return friendsMapper.insertFriendsRequestData(localUid, dto.getFriendFakeUId(), dto.getDesc(),
        System.currentTimeMillis()) > 0;
  }

  @Override
  public Boolean insertFriendsData(String uid, String friendUid) {
    return friendsMapper.insertFriendsData(uid, friendUid) > 0;
  }

  @Override
  public Integer queryFriendsRequestCountByUidFriendUid(String uid, String friendUid) {
    return friendsMapper.queryFriendsRequestCountByUidFriendUid(uid, friendUid);
  }

  @Override
  public Boolean deleteFriendsRequestData(String uid, String friendUid) {
    return friendsMapper.deleteFriendsRequestData(uid, friendUid) > 0;
  }

  @Override
  public List<RosterVO> getRosterByUid(String uid) {
    return friendsMapper.getRosterByUid(uid);
  }

  @Override
  public List<UserRosterVO> queryFriendsList(UserUIdDTO dto) {
    List<UserRosterVO> friends = friendsMapper.queryFriendsList(dto.getUid());

    for (int i = 0; i < friends.size(); i++) {
      UserRosterVO item = friends.get(i);
      if (item.getFakeUid().equals(dto.getUid())) {
        friends.remove(i);
        i--;
      }
      item.setIsFriend(true);
    }
    return friends;
  }

  @Override
  public Boolean sendAddFriendRequest(String uid, FriendUIdDTO dto) throws Exception {
    UserInfo4Cache uc = usersInfoCacheProvider.get(dto.getFriendUid());
    if (null != uc && uc.getAddFriendVerficate().equals(YesNoEnum.YES.getValue().toString())) {
      return friendMessageManager.processMT5_ADD_FRIEND_REQUEST(uid, dto);
    } else if (null != uc && uc.getAddFriendVerficate().equals(YesNoEnum.NO.getValue().toString())) {
      return friendMessageManager.processAddFriendReqAgree(dto);
    }
    return Boolean.FALSE;
  }

  @Override
  public Boolean agreeFriend(FriendUIdDTO dto) throws Exception {
    return friendMessageManager.processAddFriendReqAgree(dto);
  }

  @Override
  public Boolean refuseFriend(FriendUIdDTO dto) throws Exception {
    return friendMessageManager.processAddFriendRefused(dto);
  }

  @Override
  public R deleteFriend(FriendDeleteDTO dto) {
    // 删除好友时，最佳逻辑是提前查询一下db看看是不是已被对主提前把“我”这个好友删除了，
    // 但为了性能——节省一次db查询，此处直接让它执行db删除插件，如果发生“影响行数为0”
    // 时即表示“我”已被对方提前删除。try catch的目的就是让此db执行效果静默执行，本来
    // 也不影响什么，防止将无意义的Exception发回给用户，影响体验
    try {
      // ********************* 最后尝试删除好友关系记录 ************************//
      // 先把好友从我的好友列表中删除
      friendsMapper.deleteFriend(dto.getUid(), dto.getFriendUid());
      // 再把我从好友的列表中删除
      friendsMapper.deleteFriend(dto.getFriendUid(), dto.getUid());

      // 给别删的人发送删除好友提醒
      FriendBlackDTO fb = new FriendBlackDTO();
      fb.setFriendUserUid(dto.getFriendUid());
      fb.setLocalUserUid(dto.getUid());
      try {
        // chatLogicManager.processMT60_OF_TEMP$CHAT$MSG_A$TO$SERVER(JSON.toJSONString(fb),
        // fb.getFriendUserUid());
      } catch (Exception e) {
        throw new RuntimeException(e);
      }

    } catch (Exception e) {
      log.debug("[HTTP]在为用户" + dto.getUid() + "删除好友" + dto.getFriendUid()
          + "时进入了非正常路径（\"" + e.getMessage() + "\"），原因可能是已提前被对方"
          + "从好友列表中删除。（本行log出现不影响正常逻辑，请忽略之）");
    }
    usersInfoCacheProvider.reloadOneCache(dto.getUid());
    usersInfoCacheProvider.reloadOneCache(dto.getFriendUid());
    return R.success();
  }

  @Override
  public Boolean updateFriendRemark(String uid, FriendRemarkDTO dto) {
    int res = friendsMapper.updateFriendRemark(
        dto.getRemark(),
        dto.getMoreDesc(),
        uid,
        dto.getFriendUid());
    return res > 0;
  }

  @Override
  public R getOfflineFriendsMessages(FriendOfflineDTO dto) {
    boolean isIncludeFingerPring = "1".equals(dto.getIncludeFp());
    List<OfflineMsgDTO> allRequestFriendsInfo = messagesService.getOfflineFriendsMessages(
        isIncludeFingerPring, dto.getFromUid(), dto.getUid());

    // 获取完离线消息后，就需要把水从离线列表中删除了哦
    messagesService.deleteOfflineHistoryByFriendUserUid(dto.getUid(), dto.getFromUid());

    return R.success(allRequestFriendsInfo);
  }

  @Override
  public R queryFriendRequestCount(UserUIdDTO dto) throws Exception {
    // ** 未处理的加好友请求总数量
    Integer cntInt = friendsMapper.queryUntreatedFriendRequest(dto.getUid());
    // ** 返回给客户端的数据
    Map<String, Object> map = new HashMap<String, Object>();
    // 未处理的请求总数
    map.put("req_count", cntInt);
    return R.success(map);
  }

  /**
   * 强制保护浏览器端JSON.parese()可能存在多次JSON嵌套时，因特殊字符未被尽职转义而解析出错的问题。
   *
   * @param originalStr 入参
   * @return 结果
   */
  public static String JSONSave(String originalStr) {
    if (originalStr != null) {
      // 浏览器端的JSON.parese()函数对多层嵌套JSON中有些特殊字符没有办法正确解析，
      // 因而以下代码为了保证浏览器端的正确性，强制进行个别特殊字符的转义 - 启用于20190412日
      return originalStr
          // .replaceAll("\"", "&quot;")
          // .replaceAll("\'", "&#39;")
          // .replaceAll("\\", "\\\\")
          .replaceAll("\n", " ")// \\n
          .replaceAll("\r", " ")// \\r
          .replaceAll("\t", " ")// \\t
      // .replaceAll("\\n", " ")
      // .replaceAll("\\r", " ")
      // .replaceAll("\\t", " ")
      ;
    }

    return originalStr;
  }

  @Override
  public List<RosterVO> getRosterByDeviceNo(String deviceNo) {
    return friendsMapper.getRosterByDeviceNo(deviceNo);
  }

  @Override
  public List<OfflineFriendsRequestVO> queryFriendRequestList(String fakeUid) {
    return friendsMapper.queryFriendsRequest(fakeUid);
  }

  @Override
  public Boolean markStar(String fakeUid, String friendUid) {
    Roster roster = new Roster();
    LambdaUpdateWrapper<Roster> luw = new LambdaUpdateWrapper<>();
    luw.set(Roster::getIsStar, 1);
    luw.eq(Roster::getUserUid, fakeUid)
        .eq(Roster::getFriendUserUid, friendUid);
    return friendsMapper.update(roster, luw) > 0;
  }

  @Override
  public Boolean unmarkStar(String fakeUid, String friendUid) {
    Roster roster = new Roster();
    LambdaUpdateWrapper<Roster> luw = new LambdaUpdateWrapper<>();
    luw.set(Roster::getIsStar, 0);
    luw.eq(Roster::getUserUid, fakeUid)
        .eq(Roster::getFriendUserUid, friendUid);
    return friendsMapper.update(roster, luw) > 0;
  }

  @Override
  public Roster selectRoster(String fakeUid, String friendUid) {
    LambdaQueryWrapper<Roster> lqw = new LambdaQueryWrapper<>();
    lqw.eq(Roster::getUserUid, fakeUid);
    lqw.eq(Roster::getFriendUserUid, friendUid);
    return friendsMapper.selectOne(lqw);
  }

}
